#ifndef OBJECTDETECTOR_H
#define OBJECTDETECTOR_H

#include <QObject>
#include <QVector>
#include <QRect>
#include <QImage>
#include <QMap>

#include <opencv2/gpu/gpu.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <opencv2/objdetect/objdetect.hpp>

class QIplImage;

class ObjectDetector : public QObject
{
    Q_OBJECT
public:
    enum ObjectType {
        FACE_FRONTAL,
        FACE_FRONTAL_2,
        FACE_FRONTAL_3,
        FACE_FRONTAL_4,
        FACE_PROFILE,
        EYE,
        EYE_WITH_GLASSES,
        EYE_LEFT,
        EYE_RIGHT,
        EYE_LEFT_ALT,
        EYE_RIGHT_ALT,
        EYE_PAIR_BIG,
        EYE_PAIR_SMALL,
        BODY_UPPER,
        BODY_UPPER_ALT,
        BODY_LOWER,
        BODY_FULL,
        MOUTH,
        NOSE
    };

    ObjectDetector(ObjectType type,
                   bool useGPU = false,
                   float imageScaleFactor = 1.0f,
                   QRect regionOfInterest = QRect(),
                   float windowStartScaleFactor = 1.1f,
                   float windowEndScaleFactor = 10.0f,
                   int windowStartWidth = 3,
                   int windowStartHeight = 3);

    explicit ObjectDetector(QObject *parent = 0);

    ~ObjectDetector();

    ObjectType objectType();
    float imageScaleFactor();
    QRect regionOfInterest();
    float windowStartScaleFactor();
    float windowEndScaleFactor();
    QSize windowStartSize();

signals:
    void detectedObjects(QVector<QRect> objects);
    void detectedObjects(QVector<QRect> objects, QImage image);

public slots:
    void setObjectType(ObjectType objectType);
    void setImageScaleFactor(float scale);
    void setRegionOfInterest(QRect rect);
    void setWindowStartScaleFactor(float start);
    void setWindowEndScaleFactor(float end);
    void setWindowStartSize(int width, int height);

    QVector<QVector<QRect> > detectObjectsInROIs(QVector<QRect> rects, QImage image);
    QVector<QVector<QRect> > detectObjectsInROIs(QVector<QRect> rects, IplImage* image);
    QVector<QRect> detectObjects(QImage image);
    QVector<QRect> detectObjects(cv::Mat image);

private:
    void setupCascadeFilenames();
    QVector<QRect> rectsToQRects(cv::Rect* objects, int count);
    QVector<QRect> detectObjectsGPU(cv::Mat image);
    QVector<QRect> detectObjectsCPU(cv::Mat image);

    ObjectType type;
    bool shouldUseGPU;
    float scaleFactor;
    QRect ROI;
    float windowStartScale;
    float windowEndScale;
    QSize windowSize;
    cv::CascadeClassifier* cascadeCPU;
#ifdef HAVE_CUDA
    cv::gpu::CascadeClassifier_GPU* cascadeGPU;
#endif
    QMap<ObjectType, QString> cascadeFilenames;
};

#endif // OBJECTDETECTOR_H
